package com.micro.frog.rbac.config;

import com.micro.frog.rbac.service.UserService;
import com.micro.frog.rbac.util.CookieUtil;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * SubjectUtil 请求权限安全认证
 * 可以建多个拦截器
 * extends WebMvcConfigurerAdapter Spring 5 已过时 推荐使用 下面写法
 *
 * @author :  ljh
 * @date : 2018/4/9
 **/
@Configuration
@AllArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

    private UserService userService;

    /**
     * 检查是否登录过
     */
    private static void checkSession(HttpServletRequest request, HttpServletResponse response) {
        if (StringUtils.isEmpty(CookieUtil.getToken(request))) {
            CookieUtil.createToken(response);
        } else {
            CookieUtil.refreshToken(request, response);
        }
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        InterceptorRegistration interceptor = registry.addInterceptor(new SessionInterceptor());
        // 拦截配置
        interceptor.addPathPatterns("/admin/**");
        // 排除配置
        interceptor.excludePathPatterns("/health**");
        interceptor.excludePathPatterns("/error");
        //所有和登录有关的接口全部通过，不然会陷入无限循环
        interceptor.excludePathPatterns("/admin/login.**");
        interceptor.excludePathPatterns("/**.js", "/**.css", "/**.ico", "/**.woff", "/**.png");
    }

    /**
     * 当进入拦截器链中的某个拦截器，并执行preHandle方法后
     * 1.当preHandle方法返回false时，从当前拦截器往回执行所有拦截器的afterCompletion方法，再退出拦截器链。
     * 也就是说，请求不继续往下传了，直接沿着来的链往回跑。
     * 2.当preHandle方法全为true时，执行下一个拦截器,直到所有拦截器执行完。再运行被拦截的Controller。
     * 然后进入拦截器链，运行所有拦截器的postHandle方法,完后从最后一个拦截器往回执行所有拦截器的afterCompletion方法.
     */
    private class SessionInterceptor implements HandlerInterceptor {

        /**
         * 预处理 在请求处理之前进行调用（Controller方法调用之前）
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            checkSession(request, response);
            if (userService.hasLogin(request)) {
                return true;
            }
            response.sendRedirect("/admin/login.htm");
            return false;
        }

        /**
         * 返回处理 请求处理之后进行调用，但是在视图被渲染之前（Controller方法调用之后）
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {

        }

        /**
         * 后处理 整个请求结束之后被调用，也就是在DispatcherServlet 渲染了对应的视图之后执行（主要是用于进行资源清理工作）
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {

        }
    }
}
